﻿using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.CharacterDevelopment;
using TaleWorlds.CampaignSystem.Extensions;
using TaleWorlds.Core;
using TaleWorlds.Library;

namespace MarriageFertility.Helpers;

public static class HeroInitPropertyUtils
{
    private static readonly Random _random = new();
    
    public static void InitTrait(Hero hero)
    {
        hero.SetTraitLevel(GetTrait("Valor"), _random.Next(0, 5));
        hero.SetTraitLevel(GetTrait("Manager"), _random.Next(0, 5));
        hero.SetTraitLevel(GetTrait("Calculating"), _random.Next(0, 5));
        hero.SetTraitLevel(GetTrait("Politician"), _random.Next(0, 5));
        hero.SetTraitLevel(GetTrait("Commander"), _random.Next(0, 5));
    }
    
    private static TraitObject GetTrait(string name) => 
        TraitObject.All.First(x => x.StringId == name);
    
    public static void InitAttributeAndFocus(Hero hero)
    {
        const int baseAmount = 4;
        const int occupationBonus = 4;
        const int points = 10;
        
        hero.HeroDeveloper.UnspentAttributePoints = points;
        hero.HeroDeveloper.UnspentFocusPoints = points;
        
        // 基础属性分配
        hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Vigor, baseAmount, false);
        hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Control, baseAmount, false);
        hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Cunning, baseAmount, false);
        hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Endurance, baseAmount, false);
        hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Intelligence, baseAmount, false);
        hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Social, baseAmount, false);
        
        // 职业特定加成
        switch (hero.CharacterObject.Occupation)
        {
            case Occupation.TavernWench:
                hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Vigor, occupationBonus, false);
                hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Control, occupationBonus, false);
                AddFocuses(hero, DefaultSkills.OneHanded, DefaultSkills.TwoHanded, 
                    DefaultSkills.Crossbow, DefaultSkills.Bow, DefaultSkills.Steward);
                break;
            
            case Occupation.Townsfolk:
                hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Endurance, occupationBonus, false);
                hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Vigor, occupationBonus, false);
                AddFocuses(hero, DefaultSkills.Riding, DefaultSkills.Polearm, 
                    DefaultSkills.Throwing, DefaultSkills.Medicine);
                FillBattleEquipment(hero);
                break;
            
            case Occupation.Villager:
                hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Control, occupationBonus, false);
                hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Endurance, occupationBonus, false);
                AddFocuses(hero, DefaultSkills.Bow, DefaultSkills.Riding, 
                    DefaultSkills.Medicine, DefaultSkills.Engineering);
                break;
            
            default:
                hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Control, occupationBonus, false);
                hero.HeroDeveloper.AddAttribute(DefaultCharacterAttributes.Endurance, occupationBonus, false);
                AddFocuses(hero, DefaultSkills.Medicine, DefaultSkills.Charm, 
                    DefaultSkills.Roguery, DefaultSkills.Athletics);
                break;
        }
        
        void AddFocuses(Hero targetHero, params SkillObject[] skills)
        {
            foreach (var skill in skills)
            {
                targetHero.HeroDeveloper.AddFocus(skill, 5, false);
            }
        }
    }
    
    public static void InitHeroSkill(Hero hero)
    {
        int min = 5;
        int max = 100;
        
        // 小概率获得额外技能加成
        if (MBRandom.RandomFloat < 0.2f)
        {
            min += 30;
            max += 30;
            InformationManager.DisplayMessage(
                new InformationMessage($"{hero.Name} gained more power"));
        }
        
        // 随机分配技能等级
        foreach (var skill in Skills.All)
        {
            int changeAmount = _random.Next(min, max);
            hero.HeroDeveloper.ChangeSkillLevel(skill, changeAmount, false);
        }
        
        // 初始化技能经验值
        const bool npcSkillAutoInit = true;
        if (npcSkillAutoInit)
        {
            foreach (var skill in Skills.All)
            {
                hero.HeroDeveloper.InitializeSkillXp(skill);
            }
        }
    }
    
    public static void InitHeroForNPC(Hero hero)
    {
        InitTrait(hero);
        InitAttributeAndFocus(hero);
        FillBattleEquipment(hero);
        InitHeroSkill(hero);
    }
    
    public static void FillBattleEquipment(Hero hero)
    {
        var equipmentType = GetEquipmentType(hero.CharacterObject.Occupation);
        var battleEquipment = hero.BattleEquipment;
        const int tier = 5;
        
        // 装备基础防具
        EquipArmor(battleEquipment, hero.Culture, tier);
        
        // 根据职业类型装备武器
        switch (equipmentType)
        {
            case EquipmentType.TavernWench:
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon0, ItemObject.ItemTypeEnum.OneHandedWeapon, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon1, ItemObject.ItemTypeEnum.Shield, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon2, ItemObject.ItemTypeEnum.TwoHandedWeapon, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon3, ItemObject.ItemTypeEnum.Thrown, hero.Culture, tier);
                break;
            
            case EquipmentType.Townsfolk:
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon0, ItemObject.ItemTypeEnum.OneHandedWeapon, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon1, ItemObject.ItemTypeEnum.Shield, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon2, ItemObject.ItemTypeEnum.Polearm, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon3, ItemObject.ItemTypeEnum.Thrown, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Horse, ItemObject.ItemTypeEnum.Horse, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.HorseHarness, ItemObject.ItemTypeEnum.HorseHarness, hero.Culture, tier);
                break;
            
            case EquipmentType.Villager:
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon0, ItemObject.ItemTypeEnum.TwoHandedWeapon, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon1, ItemObject.ItemTypeEnum.Bow, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon2, ItemObject.ItemTypeEnum.Arrows, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon3, ItemObject.ItemTypeEnum.Arrows, hero.Culture, tier);
                break;
            
            default:
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon0, ItemObject.ItemTypeEnum.OneHandedWeapon, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon1, ItemObject.ItemTypeEnum.Shield, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon2, ItemObject.ItemTypeEnum.Bow, hero.Culture, tier);
                EquipWeapon(battleEquipment, EquipmentIndex.Weapon3, ItemObject.ItemTypeEnum.Arrows, hero.Culture, tier);
                break;
        }
    }
    
    private enum EquipmentType { Default, TavernWench, Townsfolk, Villager }
    
    private static EquipmentType GetEquipmentType(Occupation occupation) => occupation switch
    {
        Occupation.TavernWench => EquipmentType.TavernWench,
        Occupation.Townsfolk => EquipmentType.Townsfolk,
        Occupation.Villager => EquipmentType.Villager,
        _ => EquipmentType.Default
    };
    
    private static void EquipArmor(Equipment equipment, BasicCultureObject culture, int tier)
    {
        EquipIfNotNull(equipment, EquipmentIndex.Head, ItemObject.ItemTypeEnum.HeadArmor, culture, tier);
        EquipIfNotNull(equipment, EquipmentIndex.Cape, ItemObject.ItemTypeEnum.Cape, culture, tier);
        EquipIfNotNull(equipment, EquipmentIndex.Body, ItemObject.ItemTypeEnum.BodyArmor, culture, tier);
        EquipIfNotNull(equipment, EquipmentIndex.Gloves, ItemObject.ItemTypeEnum.HandArmor, culture, tier);
        EquipIfNotNull(equipment, EquipmentIndex.Leg, ItemObject.ItemTypeEnum.LegArmor, culture, tier);
    }
    
    private static void EquipWeapon(Equipment equipment, EquipmentIndex slot, 
        ItemObject.ItemTypeEnum type, BasicCultureObject culture, int tier)
    {
        var item = GetRandomItem(type, culture, tier);
        if (item != null)
        {
            equipment[slot] = new EquipmentElement(item);
        }
    }
    
    private static void EquipIfNotNull(Equipment equipment, EquipmentIndex slot, 
        ItemObject.ItemTypeEnum type, BasicCultureObject culture, int tier)
    {
        var item = GetRandomItem(type, culture, tier);
        if (item != null)
        {
            equipment[slot] = new EquipmentElement(item);
        }
    }
    
    private static ItemObject GetRandomItem(ItemObject.ItemTypeEnum type, BasicCultureObject culture, int tier) => 
        GetItemsByType(type, culture, tier).GetRandomElementInefficiently();
    
    private static IEnumerable<ItemObject> GetItemsByType(ItemObject.ItemTypeEnum type, 
        BasicCultureObject culture, int tier)
    {
        return Items.All
            .Where(item => item.ItemType == type)
            .OrderByDescending(item => 
                item.Culture == culture && GetTierValue(item.Tier) == tier)
            .ThenByDescending(item => GetTierValue(item.Tier))
            .Take(10); // 限制结果数量提高性能
    }
    
    private static int GetTierValue(ItemObject.ItemTiers tier) => tier switch
    {
        ItemObject.ItemTiers.Tier1 => 1,
        ItemObject.ItemTiers.Tier2 => 2,
        ItemObject.ItemTiers.Tier3 => 3,
        ItemObject.ItemTiers.Tier4 => 4,
        ItemObject.ItemTiers.Tier5 => 5,
        ItemObject.ItemTiers.Tier6 => 6,
        _ => 6
    };
    
}